﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Reflection;
using System.Configuration;
using EasyMapping.Common;
using log4net;
using System.IO;
using log4net.Config;
using EasyMapping.Common.Utility;
using EasyMapping.Common.Logging;
using System.Data.Common;

namespace EasyMapping.Core
{
    class ModelManager<T>
        where T : new()
    {
        #region " Private Fileds"

        private static Type _type;
        private static string _modelName;      
        private static ILog _logger;

        #endregion

        #region " Static Contructor "

        static ModelManager()
        {
            _type = typeof(T);
            _modelName = _type.Name;
            _logger = Log4NetUtil.GetCommonLogger();
        }

        #endregion

        #region " Get Data "

        public static T GetObject(IStoreProcedure sp)
        {
            Func<DbCommand, DbDataReader> getReader = (cmd) =>
            {
                string cmdText = sp.Name.Split('.')[1];
                DbDataReader reader = 
                    DataProviderFactory.GetDataProvider().ProvideDataByProcedure(cmd, cmdText, sp.ParaMap);
                return reader;
            };

            Func<DbDataReader, object> getObject = (reader) =>
           {
               object obj = ReflectionManager.GetInstance(_type);
               ReflectionManager.SetPropertyValue(_type, reader, ref obj);
                return obj;
           };

            return ProviderUtilAdapter<T>.GetSingleObject(getReader, getObject);
        }

        public static List<T> GetList(IStoreProcedure sp)
        {
            Func<DbCommand, DbDataReader> getReader = (cmd) =>
            {
                string cmdText = sp.Name.Split('.')[1];
                DbDataReader reader = DataProviderFactory.GetDataProvider().ProvideDataByProcedure(cmd, cmdText, sp.ParaMap);
                return reader;
            };

            Func<DbDataReader, object> getObject = (reader) =>
            {
                object obj = ReflectionManager.GetInstance(_type);
                ReflectionManager.SetPropertyValue(_type, reader, ref obj);
                return obj;
            };

            return ProviderUtilAdapter<T>.GetList(getReader, getObject);
        }

        #endregion

        #region "Save Data"

        public static Boolean SaveObject(T obj, IStoreProcedure sp)
        {
            Func<DbCommand, int> createObject = (cmd) =>
            {
                string cmdText = sp.Name.Split('.')[1];
                int count = DataProviderFactory.GetDataProvider().ChangeDataByProcedure(cmd, cmdText, sp.ParaMap, obj);
                return count;
            };

            return ProviderUtilAdapter<T>.ChangeObject(createObject) >= 1 ;
        }

        public static Boolean UpdateObject(T obj, IStoreProcedure sp)
        {
            Func<DbCommand, int> createObject = (cmd) =>
            {
                string cmdText = sp.Name.Split('.')[1];
                int count = DataProviderFactory.GetDataProvider().ChangeDataByProcedure(cmd, cmdText, sp.ParaMap, obj);
                return count;
            };

            return ProviderUtilAdapter<T>.ChangeObject(createObject) >= 1;
        }

        public static Boolean DeleteObject(T obj, IStoreProcedure sp)
        {
            Func<DbCommand, int> createObject = (cmd) =>
            {
                string cmdText = sp.Name.Split('.')[1];
                int count = DataProviderFactory.GetDataProvider().ChangeDataByProcedure(cmd, cmdText, sp.ParaMap, obj);
                return count;
            };

            return ProviderUtilAdapter<T>.ChangeObject(createObject) >= 1;
        }

        #endregion

        #region " Nested Class "       

        private class ProviderUtilAdapter<Model>
            where Model:new()
        {
            public static Model GetSingleObject(Func<DbCommand, DbDataReader> getReader, Func<DbDataReader, object> getObject)
            {
                if (DataProviderFactory.GetDataProvider().ProviderType == Providers.SQLSERVER)
                {
                    return SQLHelper.GetSingleObject<Model>(getReader, getObject); 
                }

                //To Do
                return default(Model);
            }

            public static List<Model> GetList(Func<DbCommand, DbDataReader> getReader, Func<DbDataReader, object> getObject)
            {
                if (DataProviderFactory.GetDataProvider().ProviderType == Providers.SQLSERVER)
                {
                    return SQLHelper.GetList<Model>(getReader, getObject); 
                }
                //To Do
                return default(List<Model>);
            }

            public static int ChangeObject(Func<DbCommand, int> createObject)
            {
                if (DataProviderFactory.GetDataProvider().ProviderType == Providers.SQLSERVER)
                {
                    return SQLHelper.ChangeObject<Model>(createObject);
                }
                return -1;
            }
        
        }

        #endregion
    }
}
